﻿using Grow.Module.Service;
using System.Security.Cryptography;

namespace Grow.GuidGenerator.Sequential
{
    public class GuidGenerator : IGuidGenerator
    {
        private static readonly RandomNumberGenerator RandomNumberGenerator = RandomNumberGenerator.Create();

        private readonly IServiceContext _serviceContext;
        private readonly GuidGeneratorOptions _guidGeneratorOptions;
        public GuidGenerator(IServiceContext serviceContext)
        {
            _serviceContext = serviceContext;
            _guidGeneratorOptions = _serviceContext.GetOptions<GuidGeneratorOptions>();
        }

        public Guid Create()
        {
            // 原先 10 字节的随机序列数组，减少为 8 字节
            byte[] randomBytes = new byte[8];
            RandomNumberGenerator.GetBytes(randomBytes);

            // 时间戳保持纳秒级，不额外处理
            long timestamp = DateTime.UtcNow.Ticks;

            byte[] timestampBytes = BitConverter.GetBytes(timestamp);
            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(timestampBytes);
            }

            byte[] guidBytes = new byte[16];

            switch (_guidGeneratorOptions.GuidGeneratorType)
            {
                case GuidGeneratorTypeEnum.SequentialAsString:
                case GuidGeneratorTypeEnum.SequentialAsBinary:

                    // 16位数组：前8位为时间戳，后8位为随机数
                    Buffer.BlockCopy(timestampBytes, 0, guidBytes, 0, 8);
                    Buffer.BlockCopy(randomBytes, 0, guidBytes, 8, 8);

                    // .NET中，Data1、Data2、Data3 块 分别视为 Int32、Int16、Int16
                    // 跟时间戳从 Int64 转 byte 数组后需要翻转一个理，在小端系统，需要翻转这3个块。
                    if (_guidGeneratorOptions.GuidGeneratorType == GuidGeneratorTypeEnum.SequentialAsString && BitConverter.IsLittleEndian)
                    {
                        Array.Reverse(guidBytes, 0, 4);
                        Array.Reverse(guidBytes, 4, 2);
                        Array.Reverse(guidBytes, 6, 2); // 翻转
                    }
                    break;

                case GuidGeneratorTypeEnum.SequentialAtEnd:

                    // 16位数组：前8位为随机数，后8位为时间戳
                    Buffer.BlockCopy(randomBytes, 0, guidBytes, 0, 8);
                    // 方案1：正常拼接。这种方式只能连续1年+
                    Buffer.BlockCopy(timestampBytes, 0, guidBytes, 8, 8);
                    // 方案2：将时间戳末尾的2个字节，放到 Data4 的前2个字节
                    Buffer.BlockCopy(timestampBytes, 6, guidBytes, 8, 2);
                    Buffer.BlockCopy(timestampBytes, 0, guidBytes, 10, 6);
                    break;
            }

            return new Guid(guidBytes);
        }
    }
}